/***
 * System Control Processor (CP0) Registers
 * Register constants and names required for the system control processor.
 *
 * Control Registers
 * In CP0 the general purpose registers are control registers so to speak
 * (there is no such thing as a general purpose CP0 register but there is
 * no other instruction to access them as control register access isn't
 * implemented for CP0).
 *
 * Listed here are constants for these registers as well as the status
 * register, perhaps the most important of the CP0 registers.  See
 * related files for other registers, particularly config.h.
 **/


// CP0 Control Registers
// In this header we define constants and macros for dealing with the basic control registers of
// CP0, for more specialized registers (such as the MM registers), see the associated headers

// Status Register
// SR Layout:
//  31    28 27   26   25   24   23   22    21   20   19   18  16 15 10 9    8  7    6    5  4    3  2     1     0
// | CU3-0 | RP | FR | RE | MX | PX | BEV | TS | SR | NMI |  0  |    IM7-0   | KX | SX | UX | KSU | ERL | EXL | IE |
//                                                              | IPL | IM1-0|

#define SR_ENABLE_CP3		(1 << 31)	// Can't actually have a CP3 since the FPU uses the slot
#define SR_ENABLE_CP2		(1 << 30)
#define SR_ENABLE_CP1		(1 << 29)	// FPU CP
#define SR_ENABLE_CP0		(1 << 28)	// Enabling this gives user programs access to CP0 instructions

#define SR_REDUCED_POWER	(1 << 27)	// Run in low power mode
#define SR_FPU_MODE			(1 << 26)	// When not set FPU emulates old MIPS with only 16 double registers
#define SR_REVERSE_ENDIAN	(1 << 25)	// Run user process in the opposite of host endianess
#define SR_XINSTRUCTIONS	(1 << 24)	// Enable DSP or MDMX ASE depending on implementation
#define SR_USER_ISA64		(1 << 23)	// Allows user programs to execute 64 bit instructions w/o SR(UX)
#define SR_BOOT_EVECTOR		(1 << 22)	// Use boot exception vectors in ROM at kseg1
#define SR_TLB_SHUTDOWN		(1 << 21)	// Set when the TLB has encountered a fatal error and shutdown
#define SR_SOFT_RESET		(1 << 20)	// Set to indicate that a soft-rest has occurred
#define SR_NMI_FLAG			(1 << 19)	// Set to indicate a non maskable interrupt occurred
#define SR_INT_MASK			0xFF00		// Interrupt mask to indicate which interrupts may occur
#define SR_KERN_MEM64		(1 << 7)	// Allow kernel level programs to use a 64 bit address space
#define SR_SUPER_MEM64		(1 << 6)	// Allow supervisor programs to use a 64 bit address space
#define SR_USER_MEM64		(1 << 5)	// Allow user code to use 64 bit addr space and run 64 bit instr.
#define SR_PRIV_MODE		0x18		// Stores the priv mode, 0=kernel,1=supervisor,2=user
#define SR_ERROR_LEVEL		(1 << 2)	// Set during low-level ECC error correction, memory is remapped
#define SR_EXCEPTION_LEVEL	(1 << 1)	// Set during an exception, disables exceptions, enables kern mode
#define SR_ENABLE_INT		(1 << 0)	// Enable interrupts

#define SET_SR_PRIV(f, l)	REG_SET_BITS(f, SR_PRIV_MODE, 3, l)
#define GET_SR_PRIV(f)		REG_GET_BITS(f, SR_PRIV_MODE, 3)

#define SR_PRIV_USER		2
#define SR_PRIV_SUPER		1
#define SR_PRIV_KERNEL		0

#define SET_SR_IMASK(f, i)	REG_SET_BITS(f, SR_INT_MASK, 8, i)
#define GET_SR_IMASK(f)		REG_GET_BITS(f, SR_INT_MASK, 8)

// CP0 Registers
// Older versions of MIPS originally only supported 32 CP0 Control registers, 
// however with MIPS32/64 there is now support for up to 256.  In order to remain
// backwardly compatable there are 32 registers each with 8 select values, when
// a select value is not specified it is assumed to be 0, keeping the new CP0
// registers compatible with old code/instructions.  These macros encode the
// registers in an internally useful format.

#define CP0_REG(N, S)	(((N) << 3) | ((S) & 0x7))
#define CP0_REG_N(R)	(((R) >> 3) & 0x1F)
#define CP0_REG_S(R)	((R) & 0x7)

// CP0 Registers
enum {
	kCP0Reg_SR			= CP0_REG(12, 0),	// Status register (machine configuration)
	kCP0Reg_Cause		= CP0_REG(13, 0),	// Reports the cause of an interrupt or exception
	kCP0Reg_EPC			= CP0_REG(14, 0),	// Offending PC address to restore to
	kCP0Reg_Count		= CP0_REG( 9, 0),	// Registers for a high resolution interval timer
	kCP0Reg_Compare		= CP0_REG(11, 0),
	kCP0Reg_BadVAddr	= CP0_REG( 8, 0),	// Virtual addr that caused last addr-related exception
	kCP0Reg_Context		= CP0_REG( 4, 0),	// Memory management registers, see mmu.h/tlb.h/addr.h
	kCP0Reg_EntryHi		= CP0_REG(10, 0),
	kCP0Reg_EntryLo0	= CP0_REG( 2, 0),
	kCP0Reg_EntryLo1	= CP0_REG( 3, 0),
	kCP0Reg_Index		= CP0_REG( 0, 0),
	kCP0Reg_PageMask	= CP0_REG( 5, 0),
	kCP0Reg_Random		= CP0_REG( 1, 0),
	kCP0Reg_Wired		= CP0_REG( 6, 0),
	kCP0Reg_PRId		= CP0_REG(15, 0),	// CPU type and revision number
	kCP0Reg_Config		= CP0_REG(16, 0),	// CPU configuration parameters, some r/w, some only read
	kCP0Reg_Config1		= CP0_REG(16, 1),
	kCP0Reg_Config2		= CP0_REG(16, 2),
	kCP0Reg_Config3		= CP0_REG(16, 3),
	kCP0Reg_EBase		= CP0_REG(15, 1),	// Relocate exception vectors with 4KB res. inside kseg0
	kCP0Reg_IntCtl		= CP0_REG(12, 1),	// Configuration for interrup vectors/priorities
	kCP0Reg_SRSCtl		= CP0_REG(12, 2),	// Shadow register control
	kCP0Reg_SRSMap		= CP0_REG(12, 3),	// Shadow register map
	kCP0Reg_CacheErr	= CP0_REG(27, 0),	// Fields for using Err. Cor. Codes to repair corrupt data
	kCP0Reg_ECC			= CP0_REG(26, 0),
	kCP0Reg_ErrorEPC	= CP0_REG(30, 0),
	kCP0Reg_TagLo		= CP0_REG(28, 0),	// Registers for cache manipulation, see cache.h
	kCP0Reg_DataLo		= CP0_REG(28, 1),
	kCP0Reg_TagHi		= CP0_REG(29, 0),
	kCP0Reg_DataHi		= CP0_REG(29, 1),
	kCP0Reg_Debug		= CP0_REG(23, 0),	// EJTAG debug unit registers
	kCP0Reg_DEPC		= CP0_REG(24, 0),
	kCP0Reg_DESAVE		= CP0_REG(31, 0),
	kCP0Reg_WatchLo		= CP0_REG(18, 0),	// Data watchpoint to trigger exceptions during ld/st
	kCP0Reg_WatchHi		= CP0_REG(19, 0),
	kCP0Reg_PerfCtl		= CP0_REG(25, 0),	// Performance counter registers
	kCP0Reg_PerfCnt		= CP0_REG(25, 1),
	kCP0Reg_LLAddr		= CP0_REG(17, 0),	// Link-load instruction address
	kCP0Reg_HWREna		= CP0_REG( 7, 0),	// User register privs
};

